import { read, utils, writeFile, write } from "xlsx";
import dayjs from 'dayjs';

export default function () {
    let getDataFromExcel = function (file) {
        return new Promise((resolve, reject) => {
            var reader = new FileReader();
            reader.onload = function (e) {
                var data = e.target.result;
                var workbook = read(data, { type: 'binary' });

                var sheetNames = workbook.SheetNames; // 工作表名称集合
                let dataJson = [];
                sheetNames.forEach((element) => {
                    var worksheet2 = workbook.Sheets[element];
                    var jsonArr = utils.sheet_to_json(worksheet2);
                    dataJson.push(jsonArr);
                });
                resolve(dataJson);
            };
            reader.readAsBinaryString(file);
        });
    };

    //时间格式化
    let formatDate = function (numb) {
        //excel中 numb为从1900/01/01开始的天数,初始就为1,所以传入值的时候应该先-1,后面一个-1原因未知
        numb = numb - 1;
        let time = new Date(numb * 24 * 60 * 60 * 1000);
        time.setFullYear(time.getFullYear() - 70);
        return dayjs(time).format('YYYY/MM/DD');
    };

    //从column数组获取导出exportOption
    //columns数组
    //columnKey key的字段名
    //columnTitle value的字段名
    let getExportOptionFromColumns = function (columns, columnKey, columnTitle, datas) {
        let exportOption = {
            titles: {
            },
            header: [],
            hideColumns: [],
        };

        columns.forEach(column => {
            exportOption.titles[column[columnKey]] = column[columnTitle];
            exportOption.header.push(column[columnKey]);
        });
        exportOption.hideColumns = Object.keys(datas[0]).filter(key => !exportOption.header.includes(key));
        return exportOption;
    };

    /**
 * 将数据数组导出为 Excel 文件 (.xlsx)
 * 
 * 此函数接收一个对象数组，通过指定导出选项（如列顺序、标题映射、隐藏列等），
 * 将其转换为 Excel 工作表并下载到本地。
 *
 * @param {Array.<Object>} [datas=[]] - 要导出的数据对象数组。默认为空数组。
 * @param {Object} [exportOption={}] - 导出配置选项。
 * @param {Array.<string>} [exportOption.header] - 定义导出列的顺序和包含哪些列。
 *                                                 若未提供，则使用 `datas[0]` 的所有键。
 * @param {Array.<string>} [exportOption.hideColumns] - 需要从导出中隐藏的列键名数组。
 * @param {Object.<string, string>} [exportOption.titles] - 表头映射对象，用于将数据键名替换为更友好的显示名称。
 *                                                         例如: `{ A: "AA", B: "BB" }`。
 * @param {string} [fileName='1.xlsx'] - 生成的 Excel 文件名。
 * @returns {void} 该函数无返回值，但会触发浏览器下载文件。
 * @throws {Error} 如果 `datas` 不是对象数组或 `exportOption` 结构不正确，可能会在内部处理中抛出错误。
 * @example
 * // 基本用法：使用默认选项导出数据
 * exportDatas([{name: 'Alice', age: 30}, {name: 'Bob', age: 25}]);
 * 
 * // 高级用法：自定义标题、隐藏列和文件名
 * const data = [{id: 1, name: 'Alice', score: 95}, {id: 2, name: 'Bob', score: 88}];
 * const options = {
 *   header: ['name', 'score'], // 指定顺序和要导出的列
 *   hideColumns: ['id'], // 隐藏 'id' 列
 *   titles: { name: 'Full Name', score: 'Exam Score' } // 定义友好表头
 * };
 * exportDatas(data, options, 'student_scores.xlsx');
 */
    let exportDatas = function (datas = [], exportOption = {}, fileName = '1.xlsx') {
        datas = JSON.parse(JSON.stringify(datas));

        //可以修改展示的顺序
        let header = exportOption.header ? exportOption.header : Object.keys(datas[0]);
        // let header = [];
        //展示的名称
        // titles = { A: "AA", B: "BB", C: "CC" };

        //不展示的列
        let hideColumns = exportOption.hideColumns ? exportOption.hideColumns : [];
        //隐藏不需要展示的列
        header = header.filter(item => !hideColumns.includes(item));
        for (let i = 0; i < hideColumns.length; i++) {
            let column = hideColumns[i];
            datas.forEach(item => {
                delete item[column];
            });
        }

        let newData = exportOption.titles ? [exportOption.titles, ...datas] : [...datas];

        let jsonWorkSheet = utils.json_to_sheet(newData, { header, skipHeader: true });


        let workBook = {
            SheetNames: ['Sheet1'], // 表名
            Sheets: {
                'Sheet1': jsonWorkSheet,
            }
        };
        writeFile(workBook, fileName);
    };

    /**
 * 将多个数据集导出到单个Excel文件的不同工作表中
 * 
 * 此函数接收多个数据数组和对应的导出配置选项，将每个数据集导出到同一Excel文件的不同工作表，
 * 最终生成一个包含多个工作表的.xlsx文件并下载到本地。
 *
 * @param {Array.<Array.<Object>>} [datas=[]] - 要导出的数据对象数组的数组。
 *     每个元素是一个对象数组，代表一个工作表的全部数据。
 * @param {Array.<Object>} [exportOptions=[]] - 导出配置选项数组，每个元素对应一个工作表的配置。
 * @param {Array.<string>} [exportOptions[].header] - 定义导出列的顺序和包含哪些列。
 *     若未提供，则使用对应数据数组第一个元素的所有键。
 * @param {Array.<string>} [exportOptions[].hideColumns] - 需要从导出中隐藏的列键名数组。
 * @param {Object.<string, string>} [exportOptions[].titles] - 表头映射对象，用于将数据键名替换为显示名称。
 *     例如: `{ id: "ID", name: "姓名" }`。
 * @param {string} [fileName='1.xlsx'] - 生成的Excel文件名。
 * @param {Array.<string>} [sheetNames=[]] - 工作表名称数组，每个元素对应一个工作表的名称。
 *     如果未提供或长度不足，可能会使用默认名称。
 * @returns {void} 该函数无返回值，但会触发浏览器下载文件。
 * @throws {Error} 如果参数结构不正确（如datas、exportOptions和sheetNames长度不匹配），
 *     或在内部处理中可能会抛出错误。
 * @example
 * // 基本用法：导出两个数据集到两个工作表
 * const data1 = [{name: 'Alice', age: 30}, {name: 'Bob', age: 25}];
 * const data2 = [{product: 'Apple', price: 5}, {product: 'Banana', price: 3}];
 * 
 * const options1 = { 
 *   titles: { name: 'Full Name', age: 'Age' } 
 * };
 * const options2 = { 
 *   titles: { product: 'Product Name', price: 'Price' } 
 * };
 * 
 * exportMultipleDatas(
 *   [data1, data2],
 *   [options1, options2],
 *   'combined_data.xlsx',
 *   ['Users', 'Products']
 * );
 * 
 * @example
 * // 高级用法：自定义列顺序和隐藏列
 * const data = [{id: 1, name: 'Alice', score: 95, internalCode: 'A1'}];
 * const options = {
 *   header: ['name', 'score'], // 指定顺序和要导出的列
 *   hideColumns: ['id', 'internalCode'], // 隐藏列
 *   titles: { name: 'Full Name', score: 'Exam Score' } // 定义友好表头
 * };
 * 
 * exportMultipleDatas(
 *   [data],
 *   [options],
 *   'student_data.xlsx',
 *   ['Scores']
 * );
 */
    let exportMultipleDatas = function (datas = [], exportOptions = [], fileName = '1.xlsx', sheetNames = []) {
        datas = JSON.parse(JSON.stringify(datas));

        let jsonSheets = getMultipleJsonWorkSheet(datas, exportOptions);
        let workBook = {
            SheetNames: sheetNames, // 表名
            Sheets: {
                // 'Sheet1': jsonWorkSheet,
                // 'sdf': jsonWorkSheet,
            }
        };

        for (let i = 0; i < sheetNames.length; i++) {
            workBook.Sheets[sheetNames[i]] = jsonSheets[i];
        }

        writeFile(workBook, fileName);
    };


    let getMultipleJsonWorkSheet = function (datas, exportOptions) {
        let jsonSheets = [];
        for (let i = 0; i < datas.length; i++) {

            //可以修改展示的顺序
            let header = exportOptions[i].header ? exportOptions[i].header : Object.keys(datas[i][0]);
            // let header = [];
            //展示的名称
            // titles = { A: "AA", B: "BB", C: "CC" };

            //不展示的列
            let hideColumns = exportOptions[i].hideColumns ? exportOptions[i].hideColumns : [];
            //隐藏不需要展示的列
            header = header.filter(item => !hideColumns.includes(item));
            for (let j = 0; j < hideColumns.length; j++) {
                let column = hideColumns[j];
                datas[i].forEach(item => {
                    delete item[column];
                });
            }

            let newData = exportOptions[i].titles ? [exportOptions[i].titles, ...datas[i]] : [...datas[i]];

            let jsonWorkSheet = utils.json_to_sheet(newData, { header, skipHeader: true });
            // 设置第一列（A列）的第一个单元格的数据类型为文本
            // const cell = utils.encode_cell({ c: 18, r: 1 }); // 编码单元格位置
            // console.log('object :>> ', jsonWorkSheet[cell]);
            // if (jsonWorkSheet[cell]) {
            //     jsonWorkSheet[cell].t = 's'; // 't' 表示文本类型
            //     jsonWorkSheet[cell].v = '110.0'; // 't' 表示文本类型
            // }

            // let a = jsonWorkSheet["!ref"];
            jsonSheets.push(jsonWorkSheet);
        }
        return jsonSheets;
    };

    /// 在excel中导出多个表(返回BASE64)
    /// datas为导出的数据数组
    /// exportOption为数组,其中的对象内置三个选项
    /// 1.titles为对象(用于修改表头展示)
    /// 2.hideColumns为数组(用于隐藏列))
    /// 3.header为数组(用于调整列顺序)
    /// fileName为文件名
    let getBase64MultipleDatas = function (datas = [], exportOptions = [], fileName = '1.xlsx', sheetNames = []) {
        datas = JSON.parse(JSON.stringify(datas));

        let jsonSheets = getMultipleJsonWorkSheet(datas, exportOptions);
        let workBook = {
            SheetNames: sheetNames, // 表名
            Sheets: {
                // 'Sheet1': jsonWorkSheet,
                // 'sdf': jsonWorkSheet,
            }
        };

        for (let i = 0; i < sheetNames.length; i++) {
            workBook.Sheets[sheetNames[i]] = jsonSheets[i];
        }
        var wopts = {
            bookType: 'xlsx', // 要生成的文件类型
            bookSST: false, // 是否生成Shared String Table，官方解释是，如果开启生成速度会下降，但在低版本IOS设备上有更好的兼容性
            type: 'base64'
        };
        var wbout = write(workBook, wopts);
        return wbout;
    };


    return {
        getDataFromExcel, formatDate, getExportOptionFromColumns,
        exportDatas, exportMultipleDatas, getBase64MultipleDatas,
    };
}
